#include "vas_utils.h"

namespace vas {

    Json::Value StringToJson(const std::string &data) {
        if (data.empty()) {
            throw std::runtime_error("StringToJson: data should not be empty");
        }
        Json::CharReaderBuilder builder;
        std::unique_ptr<Json::CharReader> const reader(builder.newCharReader());
        Json::Value json_data;
        JSONCPP_STRING errs;
        reader->parse(data.c_str(), data.c_str() + data.length(), &json_data, &errs);
        if (!json_data || !errs.empty()) {
            throw std::runtime_error("StringToJson: " + errs + " for str " + data);
        }
        return json_data;
    }

    int RandomInt(int a, int b) {
        if (a > b) {
            throw std::runtime_error("RandomInt: a should <= b");
        } else if (a == b) {
            return a;
        }
        std::srand((unsigned int) (time(nullptr)));
        return (std::rand() % (b - a + 1)) + a;
    }

    long GetCurrentTime() {
        struct timeval tv{};
        gettimeofday(&tv, nullptr);
        return tv.tv_sec * 1000 + tv.tv_usec / 1000;
    }

    std::string base64Decode(const char *Data, int DataByte) {
        //解码表
        const char DecodeTable[] =
                {
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        62, // '+'
                        0, 0, 0,
                        63, // '/'
                        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
                        0, 0, 0, 0, 0, 0, 0,
                        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
                        13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'
                        0, 0, 0, 0, 0, 0,
                        26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
                        39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'
                };
        std::string strDecode;
        int nValue;
        int i = 0;
        while (i < DataByte) {
            if (*Data != '\r' && *Data != '\n') {
                nValue = DecodeTable[*Data++] << 18;
                nValue += DecodeTable[*Data++] << 12;
                strDecode += (nValue & 0x00FF0000) >> 16;
                if (*Data != '=') {
                    nValue += DecodeTable[*Data++] << 6;
                    strDecode += (nValue & 0x0000FF00) >> 8;
                    if (*Data != '=') {
                        nValue += DecodeTable[*Data++];
                        strDecode += nValue & 0x000000FF;
                    }
                }
                i += 4;
            } else {
                Data++;
                i++;
            }
        }
        return strDecode;
    }

    std::string base64Encode(const unsigned char *Data, int DataByte) {
        //编码表
        const char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        //返回值
        std::string strEncode;
        unsigned char Tmp[4] = {0};
        int LineLength = 0;
        for (int i = 0; i < (int) (DataByte / 3); i++) {
            Tmp[1] = *Data++;
            Tmp[2] = *Data++;
            Tmp[3] = *Data++;
            strEncode += EncodeTable[Tmp[1] >> 2];
            strEncode += EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];
            strEncode += EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];
            strEncode += EncodeTable[Tmp[3] & 0x3F];
            if (LineLength += 4, LineLength == 76) {
                strEncode += "\r\n";
                LineLength = 0;
            }
        }
        //对剩余数据进行编码
        int Mod = DataByte % 3;
        if (Mod == 1) {
            Tmp[1] = *Data++;
            strEncode += EncodeTable[(Tmp[1] & 0xFC) >> 2];
            strEncode += EncodeTable[((Tmp[1] & 0x03) << 4)];
            strEncode += "==";
        } else if (Mod == 2) {
            Tmp[1] = *Data++;
            Tmp[2] = *Data++;
            strEncode += EncodeTable[(Tmp[1] & 0xFC) >> 2];
            strEncode += EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];
            strEncode += EncodeTable[((Tmp[2] & 0x0F) << 2)];
            strEncode += "=";
        }


        return strEncode;
    }

    std::string MatToBase64(const cv::Mat &img, std::string imgType) {
        // Mat 2 base64
        // imgType 包括png bmp jpg jpeg等opencv能够进行编码解码的文件
        // WARNING: This function will compress the image!!!
        std::string img_data;
        std::vector<uchar> vecImg;
        std::vector<int> vecCompression_params;
        vecCompression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
        vecCompression_params.push_back(90);
        imgType = "." + imgType;
        cv::imencode(imgType, img, vecImg, vecCompression_params);
        img_data = base64Encode(vecImg.data(), vecImg.size());
        return img_data;
    }

    cv::Mat Base64ToMat(std::string &base64_data) {
        cv::Mat img;
        std::string s_mat;
        s_mat = base64Decode(base64_data.data(), base64_data.size());
        std::vector<char> base64_img(s_mat.begin(), s_mat.end());
        img = cv::imdecode(base64_img, CV_LOAD_IMAGE_COLOR);
        return img;
    }

    std::string GetFormatCurrentTime() {
        std::stringstream strtime;
        std::time_t currenttime = std::time(nullptr);
        char tAll[255];
        std::strftime(tAll, sizeof(tAll), "%Y-%m-%d %H:%M:%S", std::localtime(&currenttime));
        strtime << tAll;
        return strtime.str();
    }

    void Info(const std::string &msg, const char *file, int line, const char *function) {
        std::cout << "[I] " << std::this_thread::get_id() << " " << GetFormatCurrentTime() << " " << file << ":" << line
                  << " [" << function << "] " << msg << std::endl;
    }

    void Error(const std::string &msg, const char *file, int line, const char *function) {
        std::cout << "[E] " << std::this_thread::get_id() << " " << GetFormatCurrentTime() << " " << file << ":" << line
                  << " [" << function << "] " << msg << std::endl;
    }

    std::string FileToString(const std::string &filename) {
        std::ifstream ifs(filename);
        std::ostringstream buf;
        char ch;
        while (buf && ifs.get(ch))
            buf.put(ch);
        return buf.str();
    }

    std::string Banner() {
        return "\n"
               "____    __    ____  _______  __        ______   ______   .___  ___.  _______ \n"
               "\\   \\  /  \\  /   / |   ____||  |      /      | /  __  \\  |   \\/   | |   ____|\n"
               " \\   \\/    \\/   /  |  |__   |  |     |  ,----'|  |  |  | |  \\  /  | |  |__   \n"
               "  \\            /   |   __|  |  |     |  |     |  |  |  | |  |\\/|  | |   __|  \n"
               "   \\    /\\    /    |  |____ |  `----.|  `----.|  `--'  | |  |  |  | |  |____ \n"
               "    \\__/  \\__/     |_______||_______| \\______| \\______/  |__|  |__| |_______|\n"
               "                                                                             \n"
               ".___________.  ______                                                        \n"
               "|           | /  __  \\                                                       \n"
               "`---|  |----`|  |  |  |                                                      \n"
               "    |  |     |  |  |  |                                                      \n"
               "    |  |     |  `--'  |                                                      \n"
               "    |__|      \\______/                                                       \n"
               "                                                                             \n"
               "____    ____  ___           _______.                                         \n"
               "\\   \\  /   / /   \\         /       |                                         \n"
               " \\   \\/   / /  ^  \\       |   (----`                                         \n"
               "  \\      / /  /_\\  \\       \\   \\                                             \n"
               "   \\    / /  _____  \\  .----)   |                                            \n"
               "    \\__/ /__/     \\__\\ |_______/ ";

    }

    void LoggerInit() {
        std::vector<spdlog::sink_ptr> sinks;
        sinks.emplace_back(std::make_shared<spdlog::sinks::stdout_sink_st>());
        sinks.emplace_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>(LOG_FILENAME, 1048576 * 5, 10));
        auto combined_logger = std::make_shared<spdlog::logger>(LOGGER_NAME, begin(sinks), end(sinks));
        combined_logger->set_pattern("[%t] %+");
        spdlog::register_logger(combined_logger);
    }


}
